package com.niiwoo.civet.trade.service.local.newRefund.refundDeal.core;

import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.base.enums.RefundTypeEnum;
import com.niiwoo.civet.trade.constant.AmountHandleConstant;
import com.niiwoo.civet.trade.dao.entity.Project;
import com.niiwoo.civet.trade.dao.entity.ProjectBorrowerSummary;
import com.niiwoo.civet.trade.dao.entity.ProjectGuaranteePlan;
import com.niiwoo.civet.trade.dao.entity.ProjectInvestorPlan;
import com.niiwoo.civet.trade.dao.mapper.ProjectGuaranteePlanMapperExt;
import com.niiwoo.civet.trade.dao.mapper.ProjectInvestorPlanMapperExt;
import com.niiwoo.civet.trade.dto.newRefund.ReceiveFeeDTO;
import com.niiwoo.civet.trade.enums.RepayStatusEnum;
import com.niiwoo.civet.trade.service.local.newRefund.common.RefundCommonService;
import com.niiwoo.civet.trade.utils.RepaymentUtil;
import com.niiwoo.tripod.lanmao.enums.BusinessTypeEnum;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.MathContext;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

@Service
public class FeeCalcForReceiveService {

    @Autowired
    private ProjectInvestorPlanMapperExt projectInvestorPlanMapperExt;

    @Autowired
    private ProjectGuaranteePlanMapperExt projectGuaranteePlanMapperExt;

    @Autowired
    private RefundCommonService refundCommonService;

    private static final Logger logger = LoggerFactory.getLogger(RefundCommonService.class);

    /**
     * 获取标的在compareDate前的待收金额
     * @param projectId
     * @param refundingPenaltyFee
     * @param compareDate
     * @param currentDate
     * @param penaltyRate
     * @return
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public List<ReceiveFeeDTO> getReceiveFeeDTOList(Long projectId, BigDecimal refundingPenaltyFee,
                                                    Date compareDate, Date currentDate, BigDecimal penaltyRate){
        List<ProjectInvestorPlan> projectInvestorPlanList = projectInvestorPlanMapperExt.selectNeedReceiveList(projectId, compareDate);
        List<ProjectGuaranteePlan> projectGuaranteePlanList = projectGuaranteePlanMapperExt.selectNeedReceiveList(projectId, compareDate);
        List<ReceiveFeeDTO> receiveFeeDTOS = this.loadReceiveFeeDTOList(projectInvestorPlanList, projectGuaranteePlanList, currentDate, penaltyRate, true);
        // 处理罚息
        BigDecimal remainingPenaltyFee = refundingPenaltyFee;
        for (ReceiveFeeDTO receiveFeeDTO : receiveFeeDTOS) {
            if(remainingPenaltyFee.compareTo(receiveFeeDTO.getPenaltyFee()) >= 0){
                remainingPenaltyFee = remainingPenaltyFee.subtract(receiveFeeDTO.getPenaltyFee());
            }else{
                receiveFeeDTO.setPenaltyFee(remainingPenaltyFee);
                remainingPenaltyFee = BigDecimal.ZERO;
            }
        }
        return receiveFeeDTOS;
    }

    /**
     *获取标的指定期数的待收金额
     * @param summary
     * @param periodList
     * @param currentDate
     * @param refundTypeEnum
     * @param deadlineUnit
     * @return
     */
    public List<ReceiveFeeDTO> getReceiveFeeDTOList(Project project, ProjectBorrowerSummary summary, List<Integer> periodList, Date currentDate, RefundTypeEnum refundTypeEnum, Byte deadlineUnit){
        Long projectId = summary.getProjectId();
        List<ProjectInvestorPlan> projectInvestorPlanList = projectInvestorPlanMapperExt.selectListByProjectIdAndPeriodList(projectId, periodList);
        List<ProjectGuaranteePlan> projectGuaranteePlanList = projectGuaranteePlanMapperExt.selectListByProjectIdAndPeriodList(projectId, periodList);
        List<ReceiveFeeDTO> receiveFeeDTOList = this.loadReceiveFeeDTOList(projectInvestorPlanList, projectGuaranteePlanList, currentDate,null, false);

        for (ReceiveFeeDTO receiveFeeDTO : receiveFeeDTOList) {
            // 坏账期之后的待还利息不收
            if (RepayStatusEnum.BADLOANS.getCode().equals(summary.getRepayStatus()) && receiveFeeDTO.getPeriod() > summary.getCurrentPeriod() + 1){
                receiveFeeDTO.setInterest(BigDecimal.ZERO);
            }
            //  提前结清免息
            if (RefundTypeEnum.OVERDEPT.equals(refundTypeEnum) && Byte.valueOf("1").equals(deadlineUnit)){
                if (receiveFeeDTO.getReceiveDate().after(new DateTime(currentDate).plusMonths(1).minusDays(1).toDate())
                        && !Integer.valueOf("1").equals(receiveFeeDTO.getPeriod())) {
                    receiveFeeDTO.setInterest(BigDecimal.ZERO);
                }
            }

            // 如果是按日计息还款，计算投资人应回款利息、应该减少的预收利息
            if(refundCommonService.isCalculateInterestByDay(project.getOrgId(), project.getDeadlineUnit(), receiveFeeDTO.getReceiveDate(), currentDate)){
                logger.info("calculateInterestByDay project:{},receiveDate:{},currentDate:{}", JSON.toJSON(project), receiveFeeDTO.getReceiveDate(), currentDate);
                BigDecimal dayRate = project.getBorrowRate().divide(BigDecimal.valueOf(AmountHandleConstant.YEAR_OF_DAY), MathContext.DECIMAL128);
                int currentDeadline = RepaymentUtil.getOverdueDay(project.getFullSuccessTime(), currentDate);
                // 满标日当天进行还款计息一天
                currentDeadline = currentDeadline == 0 ? 1 : currentDeadline;
                logger.info("calculateInterestByDay currentDeadline:{}", currentDeadline);
                BigDecimal interest = receiveFeeDTO.getCapital().multiply(dayRate).multiply(new BigDecimal(currentDeadline)).setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);
                logger.info("calculateInterestByDay interest:{}", interest);
                receiveFeeDTO.setExpectInterest(receiveFeeDTO.getInterest().subtract(interest));
                receiveFeeDTO.setInterest(interest);
            }
        }
        return receiveFeeDTOList;
    }

    /**
     * 获取标的待收列表
     * @param projectInvestorPlanList
     * @param projectGuaranteePlanList
     * @param currentDate
     * @param penaltyRate
     * @param reCalcPenaltyFee 是否重新计算罚息
     * @return
     */
    private List<ReceiveFeeDTO> loadReceiveFeeDTOList(List<ProjectInvestorPlan> projectInvestorPlanList, List<ProjectGuaranteePlan> projectGuaranteePlanList,
                                                     Date currentDate, BigDecimal penaltyRate, boolean reCalcPenaltyFee){
        List<ReceiveFeeDTO> allReceiveFeeDTOList = new ArrayList<>();
        List<ReceiveFeeDTO> investorReceiveFeeDTOList = this.getInvestorReceiveFeeDTOList(projectInvestorPlanList, currentDate, penaltyRate, reCalcPenaltyFee);
        List<ReceiveFeeDTO> guaranteeReceiveFeeDTOList = this.getGuaranteeReceiveFeeDTOList(projectGuaranteePlanList, currentDate, penaltyRate, reCalcPenaltyFee);
        allReceiveFeeDTOList.addAll(investorReceiveFeeDTOList);
        allReceiveFeeDTOList.addAll(guaranteeReceiveFeeDTOList);

        Collections.sort(allReceiveFeeDTOList);

        return allReceiveFeeDTOList;
    }


    /**
     * 获取投资人待收列表
     * @param list
     * @param currentDate
     * @param penaltyRate
     * @param recalcPenaltyFee 是否重新计算罚息
     * @return
     */
    private List<ReceiveFeeDTO> getInvestorReceiveFeeDTOList(List<ProjectInvestorPlan> list, Date currentDate, BigDecimal penaltyRate, boolean recalcPenaltyFee){
        List<ReceiveFeeDTO> resultList = new ArrayList<>();
        for (ProjectInvestorPlan one : list) {
            ReceiveFeeDTO result = new ReceiveFeeDTO();
            result.setPlanId(one.getId());
            result.setPeriod(one.getCurrentPeriod());
            result.setAccountId(one.getAccountId());
            result.setUserId(one.getUserId());
            result.setPlatformUserNo(one.getPlatformUserNo());
            BigDecimal receivingCapital = one.getCapital().subtract(one.getReceivedCapital());
            result.setCapital(receivingCapital);
            result.setInterest(one.getInterest().subtract(one.getReceivedInterest()));
            result.setExpectInterest(result.getInterest());
            if(recalcPenaltyFee){
                BigDecimal receivingPenaltyFee = this.getReceivingPenaltyFee(one.getOrgPenaltyFee(), receivingCapital, one.getReceivedPenaltyFee(),
                        penaltyRate, one.getPenaltyBeginDate(), currentDate);
                result.setPenaltyFee(receivingPenaltyFee);
            }else{
                result.setPenaltyFee(one.getTotalPenaltyFee().subtract(one.getReceivedPenaltyFee()));
            }
            result.setReceivedPenaltyFee(one.getReceivedPenaltyFee());
            result.setBusinessTypeEnum(BusinessTypeEnum.REPAYMENT);
            result.setInvestTime(one.getInvestTime());
            result.setInvestOrderId(one.getInvestOrderId());
            result.setReceiveDate(one.getReceivedDate());
            resultList.add(result);
        }
        return  resultList;
    }

    /**
     * 获取担保公司待收列表
     * @param list
     * @param currentDate
     * @param penaltyRate
     * @param reCalcPenaltyFee 是否重新计算罚息
     * @return
     */
    private List<ReceiveFeeDTO> getGuaranteeReceiveFeeDTOList(List<ProjectGuaranteePlan> list, Date currentDate, BigDecimal penaltyRate, boolean reCalcPenaltyFee){
        List<ReceiveFeeDTO> resultList = new ArrayList<>();
        for (ProjectGuaranteePlan one : list) {
            ReceiveFeeDTO result = new ReceiveFeeDTO();
            result.setPlanId(one.getId());
            result.setPeriod(one.getPeriod());
            result.setAccountId(one.getAccountId());
            result.setUserId(one.getUserId());
            result.setPlatformUserNo(one.getPlatformUserNo());
            BigDecimal receivingCapital = one.getCapital().subtract(one.getReceivedCapital());
            result.setCapital(receivingCapital);
            result.setInterest(one.getInterest().subtract(one.getReceivedInterest()));
            result.setExpectInterest(result.getInterest());
            if(reCalcPenaltyFee){
                BigDecimal receivingPenaltyFee = this.getReceivingPenaltyFee(one.getOrigianlPenalty(), receivingCapital, one.getReceivedPenaltyFee(),
                        penaltyRate, one.getPenaltyBeginDate(), currentDate);
                result.setPenaltyFee(receivingPenaltyFee);
            }else{
                result.setPenaltyFee(one.getTotalPenaltyFee().subtract(one.getReceivedPenaltyFee()));
            }
            result.setReceivedPenaltyFee(one.getReceivedPenaltyFee());
            result.setBusinessTypeEnum(BusinessTypeEnum.COMPENSATORY_REPAYMENT);
            result.setInvestTime(one.getInvestTime());
            result.setInvestOrderId(one.getOriginalOrderId());
            result.setReceiveDate(one.getReceiveDate());
            resultList.add(result);
        }
        return  resultList;
    }

    /**
     * 待收罚息计算
     * @param orgPenaltyFee
     * @param receivingCapital
     * @param receivedPenaltyFee
     * @param penaltyRate
     * @param penaltyBeginDate
     * @param currentDate
     * @return
     */
    private BigDecimal getReceivingPenaltyFee(BigDecimal orgPenaltyFee, BigDecimal receivingCapital, BigDecimal receivedPenaltyFee,  BigDecimal penaltyRate,
                                              Date penaltyBeginDate, Date currentDate){
        Integer days = RepaymentUtil.getOverdueDay(penaltyBeginDate,currentDate);
        days = days>0? days:0;
        return orgPenaltyFee.add(receivingCapital.multiply(penaltyRate).multiply(new BigDecimal(days)).setScale(2,BigDecimal.ROUND_HALF_EVEN)).subtract(receivedPenaltyFee);
    }
}
